// 重试管理器
// @/utils/http/RetryManager.ts

import type { InternalRequestConfig } from '@/types/http'

interface RetryConfig {
  count: number
  delay: number
  enableExponentialBackoff?: boolean
  maxDelay?: number
  retryCondition?: (error: any) => boolean
}

export class RetryManager {
  private defaultConfig: RetryConfig

  constructor(config?: Partial<RetryConfig>) {
    this.defaultConfig = {
      count: 3,
      delay: 1000,
      enableExponentialBackoff: true,
      maxDelay: 30000,
      ...config
    }
  }

  // 执行重试
  async retry<T>(
    fn: () => Promise<T>,
    requestConfig: InternalRequestConfig,
    customConfig?: Partial<RetryConfig>
  ): Promise<T> {
    const config = { ...this.defaultConfig, ...customConfig }
    const retryCount = requestConfig._retryCount || 0

    if (retryCount >= config.count) {
      throw new Error('重试次数已达上限')
    }

    // 计算延迟时间
    const delay = this.calculateDelay(retryCount, config)

    // 等待
    await this.sleep(delay)

    // 更新重试次数
    requestConfig._retryCount = retryCount + 1

    try {
      return await fn()
    } catch (error) {
      // 检查是否应该继续重试
      if (config.retryCondition && !config.retryCondition(error)) {
        throw error
      }

      // 如果还有重试次数，继续重试
      if (requestConfig._retryCount < config.count) {
        console.warn(`请求失败，${delay}ms 后进行第 ${requestConfig._retryCount + 1} 次重试`)
        return this.retry(fn, requestConfig, customConfig)
      }

      throw error
    }
  }

  // 计算延迟时间
  private calculateDelay(retryCount: number, config: RetryConfig): number {
    let delay = config.delay

    if (config.enableExponentialBackoff) {
      // 指数退避：delay * 2^retryCount
      delay = config.delay * Math.pow(2, retryCount)
    }

    // 添加随机抖动，避免大量请求同时重试
    const jitter = delay * 0.1 * Math.random()
    delay += jitter

    // 确保不超过最大延迟
    if (config.maxDelay) {
      delay = Math.min(delay, config.maxDelay)
    }

    return Math.round(delay)
  }

  // 延迟执行
  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms))
  }

  // 创建重试策略
  static createStrategy(options: {
    type: 'linear' | 'exponential' | 'fibonacci'
    baseDelay: number
    maxDelay?: number
  }): (retryCount: number) => number {
    const { type, baseDelay, maxDelay = 60000 } = options

    switch (type) {
      case 'linear':
        return (retryCount: number) => {
          const delay = baseDelay * (retryCount + 1)
          return Math.min(delay, maxDelay)
        }

      case 'exponential':
        return (retryCount: number) => {
          const delay = baseDelay * Math.pow(2, retryCount)
          return Math.min(delay, maxDelay)
        }

      case 'fibonacci':
        const fib = (n: number): number => {
          if (n <= 1) return n
          return fib(n - 1) + fib(n - 2)
        }
        return (retryCount: number) => {
          const delay = baseDelay * fib(retryCount + 1)
          return Math.min(delay, maxDelay)
        }

      default:
        return () => baseDelay
    }
  }

  // 断路器模式
  static createCircuitBreaker(options: {
    failureThreshold: number
    resetTimeout: number
  }) {
    let failures = 0
    let lastFailureTime = 0
    let state: 'closed' | 'open' | 'half-open' = 'closed'

    return {
      canRetry(): boolean {
        const now = Date.now()

        // 如果断路器打开，检查是否可以进入半开状态
        if (state === 'open') {
          if (now - lastFailureTime > options.resetTimeout) {
            state = 'half-open'
            return true
          }
          return false
        }

        return true
      },

      recordSuccess(): void {
        failures = 0
        state = 'closed'
      },

      recordFailure(): void {
        failures++
        lastFailureTime = Date.now()

        if (failures >= options.failureThreshold) {
          state = 'open'
        }
      },

      getState(): string {
        return state
      }
    }
  }
} 